using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace MyGame
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class ModelManager : DrawableGameComponent
    {
        // List of models
        List<CModel> models = new List<CModel>();

        // Shot stuff
        List<CModel> shots = new List<CModel>();
        float shotMinZ = -10000;

        List<CModel> others = new List<CModel>();
        // Shot variables
        float shotSpeed = 5;
        int shotDelay = 300;
        int shotCountdown = 0;

        Vector3 maxSpawnLocation = new Vector3(1000,1000, -10000);
        float maxRollAngle = MathHelper.Pi / 40;
        int minSpeed = 1;
        int maxSpeed = 5;
        int enemiesAmount = 0;
        int maxEnemiesAmount = 30;
        // Camera
        public Camera camera { get; protected set; }

        public ModelManager(Game game)
            : base(game)
        {
            // TODO: Construct any child components here
        }

        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        protected override void LoadContent()
        {
            models.Add(new CModel(Game.Content.Load<Model>("ship"),
                new Vector3(0, 400, 0), Vector3.Zero, new Vector3(0.4f), GraphicsDevice));

            models.Add(new CModel(Game.Content.Load<Model>("ground"),
                Vector3.Zero, Vector3.Zero, Vector3.One, GraphicsDevice));

            camera = new ChaseCamera(new Vector3(0, 400, 1500), new Vector3(0, 200, 0),
                new Vector3(0, 0, 0), GraphicsDevice);
            base.LoadContent();
        }

        void collisionDetection(GameTime gameTime)
        {
            if (models[0].Position.Y < 0)
                models[0].Position = new Vector3(models[0].Position.X, 100, models[0].Position.Z);            
            if(models[0].Position.X > 10000)
                models[0].Position = new Vector3(10000, models[0].Position.Y, models[0].Position.Z);
            if (models[0].Position.X < -10000)
                models[0].Position = new Vector3(-10000, models[0].Position.Y, models[0].Position.Z);           
        }

        void updateCamera(GameTime gameTime)
        {
            ((ChaseCamera)camera).Move(models[0].Position, models[0].Rotation);
            camera.Update();
        }

        void updateModel(GameTime gameTime)
        {
            KeyboardState keyState = Keyboard.GetState();

            Vector3 rotChange = new Vector3(0, 0, 0);
            Vector3 transition = new Vector3(0, 0, 0);
            // Determine on which axes the ship should be rotated on, if any
            if (keyState.IsKeyDown(Keys.W))
                rotChange += new Vector3(1, 0, 0);
            if (keyState.IsKeyDown(Keys.S))
                rotChange += new Vector3(-1, 0, 0);
            if (keyState.IsKeyDown(Keys.A))
                rotChange += new Vector3(0, 1, 0);
            if (keyState.IsKeyDown(Keys.D))
                rotChange += new Vector3(0, -1, 0);
            if (keyState.IsKeyDown(Keys.Q))
                transition += new Vector3(0, 0, -5);
            if (keyState.IsKeyDown(Keys.E))
                transition += new Vector3(0, 0, 5);

            models[0].Rotation += rotChange * .025f;
            models[0].Direction += rotChange;
            
            if (!keyState.IsKeyDown(Keys.Space))
                return;
            //models[0].Position += transition * (float)gameTime.ElapsedGameTime.TotalMilliseconds * 4;

            Matrix rotation = Matrix.CreateFromYawPitchRoll(
                models[0].Rotation.Y, models[0].Rotation.X, models[0].Rotation.Z);

            models[0].Position += Vector3.Transform(Vector3.Forward, rotation)
                * (float)gameTime.ElapsedGameTime.TotalMilliseconds * 4;
        }

        public override void Update(GameTime gameTime)
        {
            updateModel(gameTime);
            updateCamera(gameTime);

            FireShots(gameTime);
            updateShots(gameTime);

            if (enemiesAmount < maxEnemiesAmount)
            {
                SpawnEnemy();
            }
            updateEnemies(gameTime);
            collisionDetection(gameTime);
            base.Update(gameTime);
        }

        protected void FireShots(GameTime gameTime)
        {
            Vector3 Direction = new Vector3(0, 0, -5);
            if (shotCountdown <= 0)
            {
                if (Keyboard.GetState().IsKeyDown(Keys.L) ||
                    Mouse.GetState().LeftButton == ButtonState.Pressed)
                {
                    AddShot(
                        models[0].Position + new Vector3(0, -15, 0),
                        //((ChaseCamera)camera).Direction);
                        Direction * shotSpeed);
                    // Play shot audio
                    //PlayCue("Shot");

                    shotCountdown = shotDelay;
                }
            }
            else
                shotCountdown -= gameTime.ElapsedGameTime.Milliseconds;
        }

        private void SpawnEnemy()
        {
            Vector3 position = new Vector3(((Game1)Game).rnd.Next(
                -(int)maxSpawnLocation.X, (int)maxSpawnLocation.X),
                ((Game1)Game).rnd.Next(
                -(int)maxSpawnLocation.Y, (int)maxSpawnLocation.Y),
                maxSpawnLocation.Z);

            Vector3 direction = new Vector3(0, 0,
                ((Game1)Game).rnd.Next(
                minSpeed,
                maxSpeed));

            float rollRotation = (float)((Game1)Game).rnd.NextDouble() *
                    maxRollAngle - (maxRollAngle / 2);
            others.Add(new SpinningEnemy(
                Game.Content.Load<Model>("spaceship"),
                position, direction, 0, 0, rollRotation));

            ++enemiesAmount;
        }

        protected void updateEnemies(GameTime gameTime)
        {
            for (int i = 0; i < others.Count; ++i)
            {
                others[i].Update();

                if (others[i].GetWorld().Translation.Z < shotMinZ)
                {
                    others.RemoveAt(i);
                    --i;
                }
                else
                {
                    //for (int j = 0; j < others.Count; ++j)
                    //{
                        if (models[0].CollidesWith(others[i].Model,
                            others[i].GetWorld()))
                        {
                            others.RemoveAt(i);
                            //shots.RemoveAt(i);
                            --i;
                            break;
                        }
                    //}
                }
            }
        }

        protected void updateShots(GameTime gameTime)
        {
            // Loop through shots
            for (int i = 0; i < shots.Count; ++i)
            {
                // Update each shot
                shots[i].Update();

                //If shot is out of bounds, remove it from game
                if (shots[i].GetWorld().Translation.Z < shotMinZ)
                {
                    shots.RemoveAt(i);
                    --i;
                }
                else
                {
                    for (int j = 0; j < others.Count; ++j)
                    {
                        if (shots[i].CollidesWith(others[j].Model,
                            others[j].GetWorld()))
                        {
                            others.RemoveAt(j);
                            shots.RemoveAt(i);
                            --i;
                            break;
                        }
                    }
                }                
            }
        }

        public void AddShot(Vector3 position, Vector3 direction)
        {
            shots.Add(new SpinningEnemy(
                Game.Content.Load<Model>("ball"),
                position, direction, 0, 0, 0));
        }
        
        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            
            foreach (CModel model in models)
                if (camera.BoundingVolumeIsInView(model.BoundingSphere))
                    model.Draw(camera.View, camera.Projection);

            foreach (CModel model in shots)
                if (camera.BoundingVolumeIsInView(model.BoundingSphere))
                    model.Draw(camera);

            foreach (CModel model in others)
                if (camera.BoundingVolumeIsInView(model.BoundingSphere))
                    model.Draw(camera);

            base.Draw(gameTime);
        }
        
    }
}
